<template>
  <header class="page-header">
    <div class="title">图模绘制工具</div>
    <ul class="tools" v-if="canvas">
      <li v-for="(item, index) in tools" :key="index" @click="item.handler" class="tool">
        {{ item.name }}
        <el-color-picker
          v-if="item.isColorPicker"
          v-model="pickedColor"
          v-bind="{ predefine: predefineColors }"
          size="small"
          popper-class="my-color-picker"
          ref="colorPicker"
          @active-change="handleActiveChange"
          @change="handleChange"
          class="visually-hidden"
        />
      </li>
    </ul>
  </header>
</template>

<script setup>
import { ref, useTemplateRef } from 'vue'
import { useFabricStore } from '@/stores/fabric'
import { storeToRefs } from 'pinia'
import { exportFabricToSVG, readSvgFile, saveJson, readJson } from '@/utils/fabricFileTools'
import {
  activateMinions,
  recordRelationship,
  globalBossIds,
  globalMinionIds,
  unbindMinions,
  unbindBoss,
} from '@/utils/fabricOprationTools'
import * as fabric from 'fabric'

const backgroundColor = import.meta.env.VITE_CANVAS_BACKGROUND_COLOR
const fabricStore = useFabricStore()
const { canvas, boardHeight, boardWidth, customPropsArray } = storeToRefs(fabricStore)

const colorPicker = useTemplateRef('colorPicker')

const pickedColor = ref(backgroundColor)
const predefineColors = ref([backgroundColor])

let lastColor = pickedColor.value
const boardstrokeWidth = Number(import.meta.env.VITE_CANVAS_DRAWBOARD_STROKEWIDTH)
const backgroundImage = new fabric.Rect({
  left: -boardstrokeWidth,
  top: -boardstrokeWidth,
  fill: 'transparent',
  stroke: '#07275b',
  strokeWidth: boardstrokeWidth,
  width: boardWidth.value + 2 * boardstrokeWidth,
  height: boardHeight.value + 2 * boardstrokeWidth,
  excludeFromExport: true,
})
const clipPath = new fabric.Rect({
  left: 0,
  top: 0,
  width: boardWidth.value,
  height: boardHeight.value,
})

const tools = ref([
  {
    name: '清空',
    handler: () => {
      if (confirm('确定要清空画布吗？')) {
        // canvas.value.clear()
        // canvas.value.set({ backgroundColor: pickedColor.value })
        canvas.value.remove(...canvas.value.getObjects())
        canvas.value.discardActiveObject()
      }
    },
  },
  {
    name: '保存',
    handler: () => {
      localStorage.setItem(
        'fabric-save',
        JSON.stringify(canvas.value.toObject(customPropsArray.value)),
      )
    },
  },
  {
    name: '复原',
    handler: async () => {
      if (localStorage.getItem('fabric-save')) {
        await canvas.value.loadFromJSON(JSON.parse(localStorage.getItem('fabric-save')))
        restoreRelationship(canvas.value)
        canvas.value.renderAll()
      }
    },
  },
  {
    name: '添加SVG',
    handler: async () => {
      const svg = await readSvgFile()
      const { objects, options } = await fabric.loadSVGFromString(svg)
      const obj = fabric.util.groupSVGElements(objects, options)
      canvas.value.add(obj)
      canvas.value.renderAll()
    },
  },
  {
    name: '导出SVG',
    handler: () => {
      canvas.value.set({ clipPath })
      exportFabricToSVG(canvas.value)
      canvas.value.set({ clipPath: null })
    },
  },
  {
    name: '保存JSON',
    handler: () => {
      saveJson(JSON.stringify(canvas.value.toObject(customPropsArray.value)))
    },
  },
  {
    name: '读取JSON',
    handler: async () => {
      const json = await readJson()
      if (!json) return
      canvas.value.clear()
      await canvas.value.loadFromJSON(json)
      canvas.value.set({
        backgroundImage,
      })
      globalBossIds.clear()
      globalMinionIds.clear()
      restoreRelationship(canvas.value)
      canvas.value.renderAll()
    },
  },
  {
    name: '设置背景色',
    isColorPicker: true,
    handler: () => {
      colorPicker.value[0].show()
      lastColor = pickedColor.value
    },
  },
])

/**
 * 恢复canvas中的boss和minions关系
 * @param {fabric.Canvas} canvas
 */
const restoreRelationship = (canvas) => {
  const objects = [...canvas.getObjects()]
  const minions = objects.filter((object) => object.isMinion)
  const relationships = new Map()
  const ownerlessMinions = new Set(minions)
  for (const o of objects) {
    if (o.isMinion) continue
    if (o.isBoss) {
      relationships.has(o) || relationships.set(o, [])
      globalBossIds.add(o.id)
      for (const m of minions) {
        if (m.bossId !== o.id) continue
        relationships.get(o).push(m)
        ownerlessMinions.delete(m)
        globalMinionIds.add(m.id)
      }
    }
  }
  relationships.forEach((minions, boss) => {
    if (!minions.length) {
      unbindBoss(boss.id, canvas)
      return
    }
    recordRelationship(boss, minions)
    activateMinions(boss, minions)
  })
  if (ownerlessMinions.size) {
    unbindMinions(
      [...ownerlessMinions].map((m) => m.id),
      canvas,
    )
  }
}

const handleActiveChange = (v) => {
  canvas.value.set({ backgroundColor: v })
  canvas.value.renderAll()
}
const handleChange = (v) => {
  if (!v) {
    pickedColor.value = lastColor
  }
}
</script>

<style lang="scss" scoped>
.page-header {
  display: flex;
  gap: 1rem;
  background-color: #001245;
  color: #eee;
  box-shadow: 0px 0.5px 0.5px rgba(0, 0, 0, 0.1);
  .title {
    width: max-content;
    height: 100%;
    padding: 0 0.5rem;
    font-size: 1.2rem;
    align-content: center;
  }
  .tools {
    display: flex;
    gap: 0.2rem;
    align-items: center;
    font-size: 0.95rem;
    .tool {
      display: flex;
      align-items: center;
      height: 60%;
      padding: 0 5px;
      cursor: pointer;
      &:hover {
        color: #409eff;
        outline: 0.2px solid rgba(64, 158, 255, 0.5);
        border-radius: 4px;
        transform: translateY(2px);
      }
      :deep(.el-color-picker) {
        .el-color-picker__trigger {
          border-color: rgba(64, 158, 255, 0.5);
        }
      }
    }
  }
}
</style>
